<?php


namespace App\Support;

use App\Exceptions\BaseException;
use App\Kuafu\Base\Enum\BaseCodeEnum;
use App\Kuafu\Common\Enum\CommonCodeEnum;
use App\Kuafu\Customer\Enum\PlatformCodeEnum;
use Illuminate\Contracts\Encryption\EncryptException;
use Illuminate\Http\Request;
use Illuminate\Encryption\Encrypter;
use App\Kuafu\Common\Exceptions\EncryptException as CommonEncryptException;
use Illuminate\Support\Facades\Log;


class AppletEncrypt
{
    protected static $key;
    protected static $cipher;
    private static   $instance = null;

    public function __construct()
    {
        self::$key    = config('app.key');
        self::$cipher = config('app.cipher');
    }

    public static function getInstance()
    {
        //判断实例有无创建，没有的话创建实例并返回，有的话直接返回
        if (!(self::$instance instanceof self)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __clone() { }

    /**
     * 生成token
     * @param $unionid
     * @param $platId
     * @return string
     * @throws BaseException
     */
    public static function encryptData($unionid, $platId): string
    {
        if ($platId == PlatformCodeEnum::PLATFORM_WECHAT_SERVICE) {// 微信服务号 过期时间用30天
            $ext = $inv = 86400 * 30;
        } else {
            $ext = config('wechat.ext');
            $inv = config('wechat.inv');
        }
        $data   = [
            'time'       => time(),
            'unionid'    => $unionid,
            'platformId' => $platId,
            'ext'        => $ext,
            'inv'        => $inv,
            'salt'       => self::$cipher
        ];
        $value  = json_encode($data);
        $string = self::encrypt($value);
        return $string;
    }

    /**
     * pos订单加密
     * @param $orderId string 订单id
     * @param $key  string 加密key
     * @return string
     */
    public static function encryptOrderData($orderId, $key): string
    {
        $data   = [
            'time'    => time(),
            'orderId' => $orderId,
            'isInv'   => false,
        ];
        $data   = json_encode($data);
        $string = self::encryptShort($data, $key);
        return $string;
    }

    /**
     * 检测token是否过期,失效刷新
     * @param $token
     * @return string
     * @throws BaseException
     */
    public static function checkExpireToken($token)
    {
        //获取token信息
        $data = self::decryptData($token);
        //如果当前实现大于token失效实现，就刷新token
        if (time() > $data['time'] + $data['ext']) {
            throw new CommonEncryptException(CommonCodeEnum::ERR_TOKEN_EXPIRE);
        }
    }

    /**
     * 检查token是否失效,过期重新登录
     * @param $token
     * @throws BaseException
     * @throws CommonEncryptException
     */
    public static function checkInvalidToken($token)
    {
        //获取token信息
        $data = self::decryptData($token);
        //如果当前实现大于token失效时间，提示用户重新登录
        if (time() > $data['time'] + $data['inv']) {
            throw new CommonEncryptException(CommonCodeEnum::ERR_TOKEN_INVALID);
        }
    }

    /**
     * 解密数据转数组
     * @param $value
     * @return mixed
     * @throws BaseException
     */
    public static function decryptData($value)
    {

        $decrypt = self::decrypt($value);
        return json_decode($decrypt, true);
    }

    /**
     * 加密字符串
     * @param $value
     * @return string
     * @throws BaseException
     */
    public static function encrypt($value): string
    {
        try {
            $encrypt = new Encrypter(substr(self::$key, -32), self::$cipher);
            return $encrypt->encrypt($value);
        } catch (EncryptException $encryptException) {
            throw new BaseException(BaseCodeEnum::ERR_SERVER_ERROR, $encryptException->getMessage());
        }
    }

    /**
     * 解密字符串
     * @param $payload
     * @return mixed
     * @throws BaseException
     */
    public static function decrypt($payload)
    {
        try {
            $encrypt = new Encrypter(substr(self::$key, -32), self::$cipher);
            return $encrypt->decrypt($payload);
        } catch (EncryptException $encryptException) {
            throw new BaseException(BaseCodeEnum::ERR_SERVER_ERROR, $encryptException->getMessage());
        }
    }

    /**
     * 刷新token
     */
    public static function refreshToken($token, $platId)
    {
        $data  = self::decrypt($token);
        $token = self::encryptData($data['userId'], $platId);
        return $token;
    }

    /**
     * @param $appletToken
     * @return mixed
     * @throws BaseException
     */
    public static function getUserUnionid($appletToken)
    {
        $data = self::decryptData($appletToken);
        if (!isset($data['unionid'])) {
            throw new BaseException(BaseCodeEnum::ERR_APPLET_TOKEN);
        }

        return $data['unionid'];
    }

    /**
     * 在生成的二维码中加上logo(生成图片文件)
     * @param $url
     * @return string
     */
    public static function seedQrCode($codeData)
    {
        $shopId = $codeData['shopId'];
        include_once 'phpqrcode.php';
        $value                = $codeData['url'];//二维码数据
        $errorCorrectionLevel = 'H';//纠错级别：L、M、Q、H
        $matrixPointSize      = 10;//二维码点的大小：1到10
        \QRcode::png($value, "./storage/uploads/images/$shopId" . 'Qr.png', $errorCorrectionLevel,
            $matrixPointSize, 2);//不带Logo二维码的文件名
        $logo = './storage/uploads/images/kfzc.png';;//需要显示在二维码中的Logo图像
        $QR = "./storage/uploads/images/$shopId" . 'Qr.png';
        if ($logo !== false) {
            $QR             = imagecreatefromstring(file_get_contents($QR));
            $logo           = imagecreatefromstring(file_get_contents($logo));
            $QR_width       = imagesx($QR);
            $QR_height      = imagesy($QR);
            $logo_width     = imagesx($logo);
            $logo_height    = imagesy($logo);
            $logo_qr_width  = $QR_width / 5;
            $scale          = $logo_width / $logo_qr_width;
            $logo_qr_height = $logo_height / $scale;
            $from_width     = ($QR_width - $logo_qr_width) / 2;
            imagecopyresampled($QR, $logo, $from_width, $from_width, 0, 0, $logo_qr_width, $logo_qr_height, $logo_width,
                $logo_height);
        }
        imagepng($QR, "./storage/uploads/images/$shopId" . 'QrLogo.png');//带Logo二维码的文件名
        return config("wechat.imageUrl") . "/storage/uploads/images/$shopId" . 'QrLogo.png';

    }

    /**
     * 加密--返回端加密字符串
     * @param $data
     * @param $key
     * @return string
     */
    public static function encryptShort($data, $key)
    {
        $key  = md5($key);
        $x    = 0;
        $len  = strlen($data);
        $l    = strlen($key);
        $char = '';
        $str  = '';
        for ($i = 0; $i < $len; $i++) {
            if ($x == $l) {
                $x = 0;
            }
            $char .= $key[$x];
            $x++;
        }
        for ($i = 0; $i < $len; $i++) {
            $str .= chr(ord($data[$i]) + (ord($char[$i])) % 256);
        }
        return base64_encode($str);
    }

    /**
     * 解密短字符串
     * @param $data
     * @param $key
     * @return string
     */
    public static function decryptShort($data, $key)
    {
        $key  = md5($key);
        $x    = 0;
        $data = base64_decode($data);
        $len  = strlen($data);
        $l    = strlen($key);
        $char = '';
        $str  = '';
        for ($i = 0; $i < $len; $i++) {
            if ($x == $l) {
                $x = 0;
            }
            $char .= substr($key, $x, 1);
            $x++;
        }
        for ($i = 0; $i < $len; $i++) {
            if (ord(substr($data, $i, 1)) < ord(substr($char, $i, 1))) {
                $str .= chr((ord(substr($data, $i, 1)) + 256) - ord(substr($char, $i, 1)));
            } else {
                $str .= chr(ord(substr($data, $i, 1)) - ord(substr($char, $i, 1)));
            }
        }
        return $str;
    }


}
